import { Injectable, Logger } from '@nestjs/common';
import { VFSService } from '../vfs.service';
import {
  MCPResource,
  MCPResourceContent,
  MCPTool,
  MCPToolResult,
  MCPPrompt,
  MCPPromptResult,
  MCPError,
  MCPResponse,
  ParsedURI,
  MCP_ERROR_CODES,
  MCPErrorCode,
  ProjectContext
} from './types';

@Injectable()
export class VFSMCPServer {
  private readonly logger = new Logger(VFSMCPServer.name);

  constructor(private readonly vfsService: VFSService) {}

  // ===== 资源管理接口 =====

  /**
   * 列出所有可用资源
   */
  async listResources(projectId?: string): Promise<MCPResponse<MCPResource[]>> {
    try {
      const startTime = Date.now();

      // 获取项目中的所有文件
      const entries = await this.vfsService.readdir(projectId || '', '', {
        recursive: true,
        includeTypeEntity: true
      });

      const resources: MCPResource[] = entries.map(entry => {
        const uri = this.generateURI(projectId || '', entry.path);
        const entityType = this.determineEntityType(entry.path);
        const mimeType = this.getMimeType(entry.path);

        return {
          uri,
          name: entry.path.split('/').pop() || 'unknown',
          description: `${entityType}: ${entry.path}`,
          mimeType,
          metadata: {
            projectId: projectId || '',
            entityType,
            lastModified: entry.stats.modifyTime || Date.now(),
            size: entry.stats.size,
            hash: entry.stats.contentHash,
            title: entry.stats.title,
            description: entry.stats.description,
            // 从stats中提取其他有价值的元数据
            componentType: entry.stats.componentType,
            tsxType: entry.stats.tsxType,
            route: entry.stats.route,
            routePath: entry.stats.routePath,
            frames: entry.stats.frames,
            isDocument: entry.stats.isDocument,
            db: entry.stats.db,
            uri: entry.stats.uri,
            method: entry.stats.method,
            contentType: entry.stats.contentType,
          }
        };
      });

      return {
        success: true,
        data: resources,
        _meta: {
          requestId: this.generateRequestId(),
          timestamp: Date.now(),
          duration: Date.now() - startTime
        }
      };
    } catch (error) {
      this.logger.error('Failed to list resources', error.stack);
      return {
        success: false,
        error: {
          code: MCP_ERROR_CODES.INTERNAL_ERROR,
          message: error.message
        },
        _meta: {
          requestId: this.generateRequestId(),
          timestamp: Date.now()
        }
      };
    }
  }

  /**
   * 读取指定资源内容
   */
  async readResource(uri: string, context?: ProjectContext): Promise<MCPResponse<MCPResourceContent>> {
    try {
      const startTime = Date.now();
      const parsedUri = this.parseURI(uri);

      if (!parsedUri.projectId) {
        throw new Error('Missing projectId in URI');
      }

      // 权限检查
      if (context) {
        const hasPermission = await this.vfsService.checkPermission(
          context.userId || 0,
          parsedUri.projectId,
          parsedUri.path,
          'read'
        );

        if (!hasPermission) {
          return {
            success: false,
            error: {
              code: MCP_ERROR_CODES.RESOURCE_ACCESS_DENIED,
              message: 'Insufficient permissions to read this resource'
            }
          };
        }
      }

      const {
        content
      } = await this.vfsService.readFile(
        parsedUri.projectId,
        parsedUri.path,
      );

      const mimeType = this.getMimeType(parsedUri.path);

      return {
        success: true,
        data: {
          uri,
          mimeType,
          text: content
        },
        _meta: {
          requestId: this.generateRequestId(),
          timestamp: Date.now(),
          duration: Date.now() - startTime
        }
      };
    } catch (error) {
      this.logger.error(`Failed to read resource: ${uri}`, error.stack);
      return {
        success: false,
        error: {
          code: this.mapErrorToMCPCode(error),
          message: error.message
        },
        _meta: {
          requestId: this.generateRequestId(),
          timestamp: Date.now()
        }
      };
    }
  }

  // ===== 工具接口 =====

  /**
   * 列出可用工具
   */
  async listTools(): Promise<MCPResponse<MCPTool[]>> {
    const tools: MCPTool[] = [
      {
        name: 'convert_to_code',
        description: 'Convert JSON schema files to TypeScript/TSX code',
        inputSchema: {
          type: 'object',
          properties: {
            projectId: { type: 'string', description: 'Project ID' },
            paths: {
              type: 'array',
              items: { type: 'string' },
              description: 'Array of file paths to convert'
            },
            options: {
              type: 'object',
              properties: {
                format: { type: 'string', enum: ['tsx', 'ts', 'jsx'], description: 'Output format' },
                includeImports: { type: 'boolean', description: 'Include import statements' }
              }
            }
          },
          required: ['projectId', 'paths']
        }
      },
      {
        name: 'validate_file',
        description: 'Validate file content against project rules',
        inputSchema: {
          type: 'object',
          properties: {
            projectId: { type: 'string', description: 'Project ID' },
            path: { type: 'string', description: 'File path' },
            content: { type: 'string', description: 'File content to validate' }
          },
          required: ['projectId', 'path', 'content']
        }
      },
      {
        name: 'batch_operation',
        description: 'Perform batch file operations',
        inputSchema: {
          type: 'object',
          properties: {
            projectId: { type: 'string', description: 'Project ID' },
            operations: {
              type: 'array',
              items: {
                type: 'object',
                properties: {
                  path: { type: 'string' },
                  operation: { type: 'string', enum: ['read', 'write', 'delete'] },
                  content: { type: 'string' }
                }
              }
            },
            options: {
              type: 'object',
              properties: {
                continueOnError: { type: 'boolean' },
                parallel: { type: 'boolean' }
              }
            }
          },
          required: ['projectId', 'operations']
        }
      },
      {
        name: 'initialize_project',
        description: 'Initialize project file system',
        inputSchema: {
          type: 'object',
          properties: {
            projectId: { type: 'string', description: 'Project ID' },
            force: { type: 'boolean', description: 'Force re-initialization' }
          },
          required: ['projectId']
        }
      }
    ];

    return {
      success: true,
      data: tools,
      _meta: {
        requestId: this.generateRequestId(),
        timestamp: Date.now()
      }
    };
  }

  /**
   * 执行工具调用
   */
  async callTool(name: string, arguments_: Record<string, any>, context?: ProjectContext): Promise<MCPResponse<MCPToolResult>> {
    try {
      const startTime = Date.now();

      let result: MCPToolResult;

      switch (name) {
        case 'validate_file':
          result = await this.handleValidateFile(arguments_, context);
          break;
        case 'batch_operation':
          result = await this.handleBatchOperation(arguments_, context);
          break;
        case 'initialize_project':
          result = await this.handleInitializeProject(arguments_, context);
          break;
        default:
          throw new Error(`Unknown tool: ${name}`);
      }

      return {
        success: true,
        data: result,
        _meta: {
          requestId: this.generateRequestId(),
          timestamp: Date.now(),
          duration: Date.now() - startTime
        }
      };
    } catch (error) {
      this.logger.error(`Tool execution failed: ${name}`, error.stack);
      return {
        success: false,
        error: {
          code: this.mapErrorToMCPCode(error),
          message: error.message
        }
      };
    }
  }

  // ===== 提示模板接口 =====

  /**
   * 列出可用提示模板
   */
  async listPrompts(): Promise<MCPResponse<MCPPrompt[]>> {
    const prompts: MCPPrompt[] = [
      {
        name: 'generate_component',
        description: 'Generate React component from description',
        arguments: [
          {
            name: 'description',
            description: 'Description of the component to generate',
            required: true
          },
          {
            name: 'component_type',
            description: 'Type of component (page, component, layout)',
            required: false
          }
        ]
      },
      {
        name: 'optimize_code',
        description: 'Optimize code for better performance',
        arguments: [
          {
            name: 'code',
            description: 'Code to optimize',
            required: true
          },
          {
            name: 'optimization_type',
            description: 'Type of optimization (performance, readability, size)',
            required: false
          }
        ]
      },
      {
        name: 'fix_bugs',
        description: 'Fix bugs in code',
        arguments: [
          {
            name: 'code',
            description: 'Code with bugs',
            required: true
          },
          {
            name: 'error_description',
            description: 'Description of the error or bug',
            required: true
          }
        ]
      }
    ];

    return {
      success: true,
      data: prompts,
      _meta: {
        requestId: this.generateRequestId(),
        timestamp: Date.now()
      }
    };
  }

  /**
   * 获取提示模板内容
   */
  async getPrompt(name: string, arguments_?: Record<string, any>): Promise<MCPResponse<MCPPromptResult>> {
    try {
      let promptResult: MCPPromptResult;

      switch (name) {
        case 'generate_component':
          promptResult = await this.generateComponentPrompt(arguments_);
          break;
        case 'optimize_code':
          promptResult = await this.optimizeCodePrompt(arguments_);
          break;
        case 'fix_bugs':
          promptResult = await this.fixBugsPrompt(arguments_);
          break;
        default:
          throw new Error(`Unknown prompt: ${name}`);
      }

      return {
        success: true,
        data: promptResult,
        _meta: {
          requestId: this.generateRequestId(),
          timestamp: Date.now()
        }
      };
    } catch (error) {
      return {
        success: false,
        error: {
          code: MCP_ERROR_CODES.METHOD_NOT_FOUND,
          message: error.message
        }
      };
    }
  }

  // ===== 私有辅助方法 =====

  private generateRequestId(): string {
    return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }

  private generateURI(projectId: string, path: string): string {
    return `project://${projectId}/${path.replace(/^\//, '')}`;
  }

  private parseURI(uri: string): ParsedURI {
    const match = uri.match(/^project:\/\/([^\/]+)\/(.+)$/);
    if (!match) {
      throw new Error(`Invalid URI format: ${uri}`);
    }

    return {
      protocol: 'project',
      projectId: match[1],
      path: '/' + match[2]
    };
  }

  private determineEntityType(path: string): 'document' | 'type' | 'folder' | 'file' {
    if (path.endsWith('.tsx') || path.endsWith('.doc')) {
      return 'document';
    }
    if (path.endsWith('.ts') || path.endsWith('.json') || path.includes('types/')) {
      return 'type';
    }
    if (!path.includes('.')) {
      return 'folder';
    }
    return 'file';
  }

  private getMimeType(path: string): string {
    if (path.endsWith('.tsx')) return 'application/typescript-tsx';
    if (path.endsWith('.ts')) return 'application/typescript';
    if (path.endsWith('.json')) return 'application/json';
    if (path.endsWith('.css')) return 'text/css';
    if (path.endsWith('.js')) return 'application/javascript';
    if (path.endsWith('.jsx')) return 'application/javascript-jsx';
    return 'text/plain';
  }

  private mapErrorToMCPCode(error: any): MCPErrorCode {
    if (error.message.includes('not found')) return MCP_ERROR_CODES.RESOURCE_NOT_FOUND;
    if (error.message.includes('permission')) return MCP_ERROR_CODES.RESOURCE_ACCESS_DENIED;
    if (error.message.includes('validation')) return MCP_ERROR_CODES.VALIDATION_ERROR;
    if (error.message.includes('exists')) return MCP_ERROR_CODES.RESOURCE_ALREADY_EXISTS;
    return MCP_ERROR_CODES.INTERNAL_ERROR;
  }

  // ===== 工具处理方法 =====

  private async handleValidateFile(args: any, context?: ProjectContext): Promise<MCPToolResult> {
    const { projectId, path, content } = args;

    // 这里需要实现文件验证逻辑
    // 暂时返回模拟结果
    return {
      content: [{
        type: 'text',
        text: `File ${path} validation completed. Status: Valid ✅`
      }]
    };
  }

  private async handleBatchOperation(args: any, context?: ProjectContext): Promise<MCPToolResult> {
    const { projectId, operations, options = {} } = args;

    const results = [];
    for (const op of operations) {
      try {
        let result;
        switch (op.operation) {
          case 'read':
            result = await this.vfsService.readFile(projectId, op.path, {});
            break;
          case 'write':
            result = await this.vfsService.writeFile(projectId, op.path, op.content, {});
            break;
          default:
            throw new Error(`Unsupported operation: ${op.operation}`);
        }
        results.push({ path: op.path, success: true, result });
      } catch (error) {
        results.push({ path: op.path, success: false, error: error.message });
        if (!options.continueOnError) {
          throw error;
        }
      }
    }

    return {
      content: [{
        type: 'text',
        text: `Batch operation completed:\n${results.map(r =>
          `${r.path}: ${r.success ? '✅' : '❌'} ${r.error || ''}`
        ).join('\n')}`
      }]
    };
  }

  private async handleInitializeProject(args: any, context?: ProjectContext): Promise<MCPToolResult> {
    const { projectId, force = false } = args;

    const result = await this.vfsService.initializeFileSystem(projectId, {
      _id: projectId,
      name: `Project ${projectId}`
    } as any);

    return {
      content: [{
        type: 'text',
        text: `Project initialization completed:\n` +
          `Success: ${result.success}\n` +
          `Updated documents: ${result.updatedDocuments}\n` +
          `Duration: ${result.duration}ms\n` +
          `Errors: ${result.errors.length}`
      }]
    };
  }

  // ===== 提示模板生成方法 =====

  private async generateComponentPrompt(args?: any): Promise<MCPPromptResult> {
    const description = args?.description || 'A new component';
    const componentType = args?.component_type || 'component';

    return {
      description: `Generate a ${componentType} based on description`,
      messages: [
        {
          role: 'user',
          content: {
            type: 'text',
            text: `Please generate a ${componentType} with the following description:\n\n${description}\n\n` +
              `Requirements:\n` +
              `- Use TypeScript\n` +
              `- Follow React best practices\n` +
              `- Include proper prop types\n` +
              `- Add comments for complex logic\n` +
              `- Make it accessible and responsive`
          }
        }
      ]
    };
  }

  private async optimizeCodePrompt(args?: any): Promise<MCPPromptResult> {
    const code = args?.code || '';
    const optimizationType = args?.optimization_type || 'performance';

    return {
      description: `Optimize code for ${optimizationType}`,
      messages: [
        {
          role: 'user',
          content: {
            type: 'text',
            text: `Please optimize the following code for ${optimizationType}:\n\n\`\`\`typescript\n${code}\n\`\`\`\n\n` +
              `Focus on:\n` +
              `- ${optimizationType} improvements\n` +
              `- Code readability\n` +
              `- Best practices\n` +
              `- Error handling\n` +
              `- Type safety`
          }
        }
      ]
    };
  }

  private async fixBugsPrompt(args?: any): Promise<MCPPromptResult> {
    const code = args?.code || '';
    const errorDescription = args?.error_description || '';

    return {
      description: 'Fix bugs in code',
      messages: [
        {
          role: 'user',
          content: {
            type: 'text',
            text: `Please fix the bugs in the following code:\n\n\`\`\`typescript\n${code}\n\`\`\`\n\n` +
              `Error description:\n${errorDescription}\n\n` +
              `Please:\n` +
              `- Identify the root cause\n` +
              `- Fix the bug\n` +
              `- Add error prevention\n` +
              `- Explain the fix\n` +
              `- Suggest improvements`
          }
        }
      ]
    };
  }
}